Basic Syntax
Every Rust program has at least one function: main.
fn main() {
println!("Hello, Rust!");
}
| Part | Meaning |
|---|---|
fn | Keyword to define a function |
main | Entry point of the program |
{} | Function body |
println! | Macro to print output |
; | Ends a statement |
Statements vs Expressions
Rust is expression-based, unlike C or Java.
- Statement does something but returns no value (
let x = 5;). - Expression evaluates to a value (
5 + 3)
let y = {
let x = 3;
x + 1 // no semicolon → expression
};
y becomes 4
Variables and Mutability
In Rust, variables are created using the let keyword.
let x = 10;
// x = 20; ❌ error
Rust variables are immutable by default (safety feature).
Why Rust Does This
- Prevent accidental changes
- Improve safety
- Make code easier to reason about
- Enable compiler optimizations
If something must change, you must say it explicitly.
Mutable Variables
To allow a variable to change, use mut.
let mut x = 10;
x = 20; // ✅ allowed
| Keyword | Meaning |
|---|---|
let | Declare variable |
mut | Make variable mutable |
Mutability and References (Preview)
let mut x = 10;
let y = &x;
// x = 20; ❌ cannot modify while borrowed
Rust prevents data races at compile time
This becomes important in ownership & borrowing
Data Types (Basics)
Rust is statically typed, but usually infers types.
Rust Data Types Categories
Rust has two main categories of data types:
| Category | Description |
|---|---|
| Scalar | Holds a single value |
| Compound | Holds multiple values |
Scalar Data Types
Scalar types represent a single value.
Rust has four scalar types:
- Integers
- Floating-point numbers
- Booleans
- Characters
Integer Types
Integers are whole numbers (no decimals).
| Type | Meaning |
|---|---|
i | Signed (positive + negative) |
u | Unsigned (only positive) |
let a: i32 = 10;
let b = 20; // inferred as i32
i32→ signed integeru32→ unsigned integerf64→ floating pointbool→ true / falsechar→ single Unicode character
Floating Point Types
Floating-point numbers represent decimals.
| Type | Size |
|---|---|
f32 | 32-bit |
f64 | 64-bit (default) |
Character Type (char)
Rust char:
- Uses single quotes
- Represents a Unicode scalar value
- Is 4 bytes (not 1 byte)
let x: i32 = 42;
let pi: f64 = 3.14;
let is_rust_fun: bool = true;
let letter: char = 'R';
Rust supports Unicode by default
Compound Data Types
Compound types group multiple values into one type.
Rust has two primitive compound types:
- Tuples
- Arrays
Tuples
- Hold multiple values (
let person = ("Alice", 25, true);) - Have different types
- Have a fixed size
Tuple Destructuring: let (name, age, active) = person;
Accessing Tuple Values: let name = person.0;
Arrays
- Store multiple values of same type
- Have fixed length
- Stored in stack memory
let scores: [i32; 3] = [80, 90, 100];
[i32; 3] | Meaning |
|---|---|
i32 | Type of elements |
3 | Number of elements |
A slice is a reference to part of a collection.
let arr = [10, 20, 30, 40];
let slice = &arr[1..3];
s contains: [20, 30]
Arrays vs Tuples
| Feature | Tuple | Array |
|---|---|---|
| Types | Different allowed | Same only |
| Size | Fixed | Fixed |
| Access | .0, .1 | [index] |
| Use case | Group related values | Lists of data |
Constants
- Are always immutable
- Must have a type
- Use
SCREAMING_SNAKE_CASE
const MAX_USERS: u32 = 100;
Static Variables (Brief Intro)
static LANGUAGE: &str = "Rust";
- Stored in a fixed memory location
- Rarely used by beginners
- Different from
const
Shadowing (Rust-Specific Feature)
Rust allows re-declaring variables with the same name.
let x = 5;
let x = x + 1;
let x = x * 2;
println!("{}", x); // 12
Shadowing ≠ mutability
Creates a new variable
Mutability changes a value
Shadowing creates a new variable
Why Shadowing Is Useful
Example: Type Change
let spaces = " ";
let spaces = spaces.len();
Why mut Can’t Do This
let mut spaces = " ";
spaces = spaces.len(); // ❌ type mismatch
Shadowing allows type transformation
mut does not
Control Flow: if, else
let number = 7;
if number > 5 {
println!("Greater than 5");
} else {
println!("5 or less");
}
if as Expression
let result = if number > 5 { 10 } else { 0 };
Both branches must return same type
match
match compares a value against patterns and executes the matching branch.
Think of it as: switch on steroids
let day = 3;
match day {
1 => println!("Monday"),
2 => println!("Tuesday"),
3 => println!("Wednesday"),
_ => println!("Invalid day"),
}
| Part | Meaning |
|---|---|
=> | Pattern match arrow |
_ | Catch-all pattern |
match is also an expression.
let number = 5;
let result = match number {
0 => "Zero",
1 => "One",
_ => "Many",
};
Pattern Matching with Ranges
let score = 78;
match score {
90..=100 => "A",
80..=89 => "B",
70..=79 => "C",
_ => "F",
};
Matching Enums (Very Common)
enum Direction {
North,
South,
East,
West,
}
let dir = Direction::North;
match dir {
Direction::North => println!("Up"),
Direction::South => println!("Down"),
Direction::East => println!("Right"),
Direction::West => println!("Left"),
}
if let (Shortcut for match)
let value = Some(5);
if let Some(x) = value {
println!("Value is {}", x);
}
Cleaner when you only care about one pattern
Loops
loop (infinite loop)
let mut count = 0;
let result = loop {
count += 1;
if count == 5 {
break count * 2;
}
};
loop can return values using break.
while
let mut n = 3;
while n > 0 {
println!("{}", n);
n -= 1;
}
for (most common)
for i in 1..=5 {
println!("{}", i);
}
| Syntax | Meaning |
|---|---|
1..5 | 1 to 4 |
1..=5 | 1 to 5 |
Comments
- Single-line
// This is a comment - Multi-line
/*
Multi-line comment
*/
Basic Collections
Tuple (fixed size, mixed types)
let person = ("Alice", 30, true);
println!("{}", person.0);
Array (fixed size, same type)
let numbers = [1, 2, 3, 4];
println!("{}", numbers[0]);
Strings (Very Important)
String Literal (&str)
let name = "Rust";
String (heap allocated, growable)
let mut name = String::from("Rust");
name.push_str(" Language");
Basic Ownership Preview (Light Intro)
let s1 = String::from("hello");
let s2 = s1;
// println!("{}", s1); ❌ error
Ownership moved from s1 → s2
Full Example Program
fn main() {
let mut score = 50;
score += 10;
if score >= 60 {
println!("Pass");
} else {
println!("Fail");
}
for i in 1..=3 {
println!("Attempt {}", i);
}
}
What This Demonstrates
- Variables & mutability
ifexpressionsforloop- Printing output